﻿using System;
using System.Text;
using System.Net.Sockets;
using System.Net;

namespace NewCROStarter
{
    //协议代码
    public enum Protocol
    {
        TCP = 6,
        UDP = 17,
        Unknown = -1
    };

    public class ROsniffer
    {
        //要监听的pid
        private int PID;
        //是否启动监听
        private bool IsCaputerStarted;
        private Socket MainSocket;
        private IPEndPoint LocalEndPoint;
        private byte[] buffer = new byte[4096];

        //以pid初始化
        public ROsniffer(int pid)
        {
            PID = pid;
        }

        //启动监听
        public void Start()
        {
            if (IsCaputerStarted)   MainSocket.Close();
            IsCaputerStarted = true;
            //假定当前用户已登录到mapserver，将local endpoint储存
            foreach (TcpRow tcprow in ManagedIpHelper.GetExtendedTcpTable(true))
            {
                //pid=指定pid，且tcp已建立连接
                if (tcprow.ProcessId == PID && tcprow.State == System.Net.NetworkInformation.TcpState.Established)
                {
                    LocalEndPoint = new IPEndPoint(IPAddress.Parse(tcprow.LocalEndPoint.Address.ToString()), 0);
                    //textBox2.Text += DateTime.Now.Hour.ToString() + ":" + DateTime.Now.Minute.ToString() + ":" + DateTime.Now.Second.ToString() + ":" + DateTime.Now.Millisecond.ToString() + " Local:" + tcprow.LocalEndPoint.ToString() + " Remote:" + tcprow.RemoteEndPoint.ToString() + "\r\n";
                }
            }
            MainSocket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP);
            MainSocket.Bind(LocalEndPoint);
            MainSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.HeaderIncluded, true);    //设置监听ip包、带ip包头
            byte[] byTrue = new byte[4] { 1, 0, 0, 0 }; //RecvALL ON
            byte[] byOut = new byte[4] { 1, 0, 0, 0 };  //byout无用
            MainSocket.IOControl(IOControlCode.ReceiveAll, byTrue, byOut);
            MainSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(OnReceive), null);    //开始接收数据
        }

        public void Stop()
        {
            if (IsCaputerStarted)
            {
                IsCaputerStarted = false;
                MainSocket.Close();
            }
        }

        //接收到封包
        private void OnReceive(IAsyncResult ar)
        {
            try
            {
                int RecvCounter = MainSocket.EndReceive(ar);
                ParseData(buffer, RecvCounter);
                //如果未要求停止接收，就继续接收下一组数据
                if (IsCaputerStarted)
                {
                    buffer = new byte[4096];
                    MainSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(OnReceive), null);
                }
            }
            catch (ObjectDisposedException) { }
            catch (Exception ex) 
            {
                //MessageBox.Show(ex.Message, "RO数据包监听模块", MessageBoxButtons.OK, MessageBoxIcon.Error); 
            }
        }

        //封包处理
        private void ParseData(byte[] buffer, int RecvCounter)
        {
            IPHeader ipheader = new IPHeader(buffer, RecvCounter);
            //仅当ip头显示该包是tcp类型时
            if ((Protocol)ipheader.ProtocolType == Protocol.TCP)
            {
                TCPHeader tcpheader = new TCPHeader(ipheader.Data, ipheader.MessageLength);
                //循环所有已开端口(=netstat -ano)
                foreach (TcpRow tcprow in ManagedIpHelper.GetExtendedTcpTable(true))
                {
                    //只处理数据段长度>0的、目标地址和端口与当前pid相同的数据
                    //IPAddress不能直接比较，必须tostring才行
                    if (tcpheader.MessageLength > 0 && ipheader.DestinationAddress.ToString() == tcprow.LocalEndPoint.Address.ToString() && tcpheader.DestinationPort == tcprow.LocalEndPoint.Port.ToString() && PID == tcprow.ProcessId)
                    {
                        //debug output:输出封包所有内容
                        //string timestr = DateTime.Now.Hour.ToString() + ":" + DateTime.Now.Minute.ToString() + ":" + DateTime.Now.Second.ToString() + ":" + DateTime.Now.Millisecond.ToString();
                        //string datastr = " recv " + tcpheader.MessageLength.ToString() + " bytes from " + ipheader.SourceAddress.ToString() + ":" + tcpheader.SourcePort + "\r\n";
                        //for (ushort i = 0; i < tcpheader.MessageLength; i++)
                        //{
                        //    datastr += tcpheader.Data[i].ToString("X2") + " ";
                        //}
                        //datastr += "\r\n";
                        //textBox1.Text += timestr + datastr;

                        //87 00 = character_moves
                        if (tcpheader.Data[0] == 0x87 && tcpheader.Data[1] == 0x00)
                        {
                            int x_from = tcpheader.Data[6] * 4 + (tcpheader.Data[7] & 0xc0) / 64;
                            int y_from = (tcpheader.Data[7] & 0x3f) * 16 + (tcpheader.Data[8] & 0xf0) / 16;
                            int x_to = (tcpheader.Data[9] & 0xfc) / 4 + (tcpheader.Data[8] & 0x0f) * 64;
                            int y_to = (tcpheader.Data[9] & 0x03) * 256 + tcpheader.Data[10];
                            //textBox3.Text += "角色移动：从" + x_from.ToString() + "x" + y_from.ToString() + "到" + x_to.ToString() + "x" + y_to.ToString() + "\r\n";
                            //触发事件
                            CharacterMovesEventArgs CharMoveArgs = new CharacterMovesEventArgs(x_from, y_from, x_to, y_to);
                            CharacterMoves(this, CharMoveArgs);
                        }
                        //92 00 = map_changed
                        if (tcpheader.Data[0] == 0x92 && tcpheader.Data[1] == 0x00)
                        {
                            //取得新mapserver的ip地址和端口(第23个节开始的4个字节)，目前无用
                            //byte[] iparray =new byte[4];
                            //Array.Copy(tcpheader.Data, 22, iparray, 0, 4);
                            //IPAddress ipa = new IPAddress(iparray);
                            //int map_port = BitConverter.ToInt16(tcpheader.Data, 26);
                            //get map name
                            string mapname = Encoding.ASCII.GetString(tcpheader.Data, 2, 16).TrimEnd('\0');
                            //删掉地图文件名结尾的扩展名
                            mapname = mapname.Replace(".gat", "");
                            int map_x, map_y;
                            //get init coords
                            map_x = BitConverter.ToInt16(tcpheader.Data, 18);
                            map_y = BitConverter.ToInt16(tcpheader.Data, 20);
                            //textBox3.Text += "地图变更：" + mapname + " " + map_x.ToString() + " x " + map_y.ToString() + "\r\n";
                            //触发事件
                            MapChangedEventArgs MapChangedArgs = new MapChangedEventArgs(mapname, map_x, map_y);
                            MapChanged(this, MapChangedArgs);
                        }
                        //91 00 = map_changed (map server not change?)
                        if (tcpheader.Data[0] == 0x91 && tcpheader.Data[1] == 0x00)
                        {
                            //get map name
                            string mapname = Encoding.ASCII.GetString(tcpheader.Data, 2, 16).TrimEnd('\0');
                            //删掉地图文件名结尾的扩展名
                            mapname = mapname.Replace(".gat", "");
                            int map_x, map_y;
                            //get init coords
                            map_x = BitConverter.ToInt16(tcpheader.Data, 18);
                            map_y = BitConverter.ToInt16(tcpheader.Data, 20);
                            //textBox3.Text += "地图变更：" + mapname + " " + map_x.ToString() + " x " + map_y.ToString() + "\r\n";
                            //触发事件
                            MapChangedEventArgs MapChangedArgs = new MapChangedEventArgs(mapname, map_x, map_y);
                            MapChanged(this, MapChangedArgs);
                        }
                    }
                }
            }
        }
        
        //可处理的事件声明
        //地图改变
        public delegate void MapChangedEventHandler(object sender, MapChangedEventArgs ev);
        public static event MapChangedEventHandler MapChanged;
        //角色移动
        public delegate void CharacterMovesEventHandler(object sender, CharacterMovesEventArgs ev);
        public static event CharacterMovesEventHandler CharacterMoves;
    }
}
